题面传送门:B4392 [常州市赛 2025] 压缩
题目大意
给个含
0,1与通配符#的字符串(通配符可任意赋值为0,1),相同的字串可以消到只剩下一个,求消完后最短的字串长度(答案唯一)。
思路讲解
可以从测试点的特殊性质入手。若字符串中无 0,则说明剩下的一定是 1 或通配符,通配符赋值为 1,答案为 1。同理,若没有 1,答案就是 0。
若字符串长度不超过 ,则答案串的长度不会超过 。列举答案串的所有情况如下:
| 字符串长度 | 情况 | 情况 | 情况 | 情况 | 情况 | 情况 | 情况 | 情况 |
|---|---|---|---|---|---|---|---|---|
| 1 | 1 | 0 | ||||||
| 2 | 00 (压缩为 0) | 01 | 10 | 11 (压缩为 1) | ||||
| 3 | 000(压缩为 0) | 001 (压缩为 01) | 010 | 011(压缩为 01) | 100(压缩为 10) | 101 | 110(压缩为 10) | 111 (压缩为 1) |
情况数屈指可数,进一步思考后发现,这些情况其实就只有以下几种答案:
1,0,01,10,101,010。
观察这些答案和原情况的关系,得出来一个基本分类讨论框架:
- 如果
1与0不同时存在,那么即使有通配符,也可以构造一个长度为 的答案。 - 如果原串长度大于等于 ,且其头尾不等,那么中间部分(长度为 无中间,直接输出)的每一个数都可以通过头尾两个不同的数构造子串进行消除,消除到
01或10。 - 若长度大于 ,头尾相等,则也可以构造子串消除到
010或101。
发现了疑点,通配符该怎么办呢?如果字符串不满足上方的条件 ,那就让其优先满足条件 ,因为其答案相对较短。找到通配符所在位置,与另外一个头或尾位置字符相反就可以了。
不可能有通配符同时在头尾的情况,若同时在头尾,构造出来条件 会发现有两个答案。
此框架有推广性,可以用于任意长度的字符串,所以问题就解决了。
代码实现
完整代码
#include<bits/stdc++.h>using namespace std;string s;char c1,c2;bool b[2];int main(){ cin>>s; for(int i=0;i<s.size();i++){ if(s[i]!='#') b[s[i]-'0']=1; } if(b[1]==1&&b[0]==0){ cout<<1; }else if(b[1]==0&&b[0]==1){ cout<<0; }else{ c1=s[0];c2=s[s.size()-1]; if(c1!=c2){ if(c1=='#'){ if(c2=='0') cout<<"10"; else cout<<"01"; }else if(c2=='#'){ if(c1=='1') cout<<"10"; else cout<<"01"; }else{ cout<<c1<<c2; } }else{ if(c1=='0'){ cout<<"010"; }else if(c1=='1'){ cout<<"101"; } } } return 0;}













